#include <unordered_map>
#include <vector>
#include <iostream>

#define TMP_TEST_PLIMIT 5

//物品
struct ItemData
{
	ItemData() : item_id(0), num(0), pile_limit(1) {}

	void Reset()
	{
		item_id = 0;
		num = 0;
		pile_limit = 1;
	}

	ItemData& operator=(const ItemData& other)
	{
		if (this == &other) return *this;

		this->item_id = other.item_id;
		this->num = other.num;
		return *this;
	}


	//是否有效
	bool Invalid() { return 0 != item_id; }

	//设置堆叠上限
	bool SetPileLimitNum(int num)
	{
		if (num <= 0)	return false;
		pile_limit = num;
		return true;
	}

	int GetPileLimitNum() { return TMP_TEST_PLIMIT; }

	int item_id;		//物品id
	int num;			//数量
	int pile_limit;		//堆叠上限
};

//物品管理
class ItemDataManager
{
private:
	static constexpr int ITEM_NUM = 65535;
	ItemDataManager()
	{
		for (int i = 0; i < ITEM_NUM; ++i)
		{
			m_item_pool[i] = nullptr;
		}
	}
	~ItemDataManager()
	{
		for (int i = 0; i < ITEM_NUM; ++i)
		{
			if (m_item_pool[i] != nullptr)	delete m_item_pool[i];
		}
	}

	ItemData* m_item_pool[ITEM_NUM];
public:
	static ItemDataManager* Instance()
	{
		static ItemDataManager manager;
		return &manager;
	}

	int GetItemPileLimitNum(int id)
	{
		return TMP_TEST_PLIMIT;

		if (id < 0 || id >= ITEM_NUM)	return 0;

		if (nullptr == m_item_pool[id])	return m_item_pool[id]->pile_limit;
	}
};

class Bag
{
private:
	static constexpr int MAX_BAG_CAP = 200;	//最大存储数量
	enum MAP_OPER_TYPE
	{
		MAP_OPER_TYPE_MIN,
		MAP_OPER_TYPE_DEL,
		MAP_OPER_TYPE_ADD,
		MAP_OPER_TYPE_MAX,
	};

	int count;	//已经使用的格子数量
	ItemData item_list[MAX_BAG_CAP];

	std::unordered_map<int, std::vector<int>> m_item_vec_map; //key -> vecotr
public:
	Bag()
	{
		count = 0;
		for (int i = 0; i < MAX_BAG_CAP; ++i)	item_list[i].Reset();
	}
	~Bag() {}

	//放入物品
	bool PutItems(int items, int num);

	//取出物品
	void TakeItem(int storage_index, int item_id, int num, ItemData& out);

	//销毁物品
	void DiscardItem(int storage_indx);

	//整理物品
	void ArrangeBag();

	//测试
	void Print();
private:
	//查找物品位置
	std::vector<int>* findItemStorageIdxVec(int item_id);
	//通过物品管理器获取物品配置
	int getItemDataCfgByID(int item_id);
	//获取背包中idx上的数据
	ItemData* getStorageByidx(int storage_index);
	//移动最后一个元素到指定位置 -1表示没有任何操作
	int resortStorage(int storage_index);
	//维护map
	void updateItemMap(int item_id, int index, int oper_type);
};

bool Bag::PutItems(int item_id, int num)
{
	//如果参数有误直接返回
	if (item_id <= 0 || num <= 0)	return false;


	//寻找位置
	std::vector<int>* idx = (this->findItemStorageIdxVec(item_id));

	int old_num = num;
	std::vector<int> change_index;
	change_index.clear();

	//放入物品 先查找可以堆叠的情况
	for (int i = 0; idx && i < static_cast<int>((*idx).size()); ++i)
	{
		if (num <= 0)	break;

		//获取格子信息
		ItemData* info = this->getStorageByidx((*idx)[i]);
		if (!info || !info->Invalid())	continue;

		if (info->GetPileLimitNum() == info->num)	continue;

		//存入
		int reduce_num = info->GetPileLimitNum() - info->num;
		if (reduce_num - num > 0)
		{
			info->num += num;
			num = 0;
		}
		else
		{
			info->num += reduce_num;
			num -= reduce_num;
		}

		//改变的信息格子放入
		change_index.emplace_back((*idx)[i]);
	}

	//放入物品 空位置
	while (num > 0)
	{
		if (this->count >= MAX_BAG_CAP)
		{
			break;
		}

		int pile_num = this->getItemDataCfgByID(item_id);

		this->item_list[this->count].item_id = item_id;
		this->item_list[this->count].num = num > pile_num ? pile_num : num;
		//维护map
		this->updateItemMap(item_id, this->count, MAP_OPER_TYPE_ADD);

		this->count++;
		num = num > pile_num ? num - pile_num : 0;
	}

	//消耗实际放入物品
	int rel_consume = old_num - num;

	//将发生变动的数组推送

	return true;
}

void Bag::TakeItem(int storage_index, int item_id, int num, ItemData& out)
{
	//获取格子信息
	ItemData* storage_info = this->getStorageByidx(storage_index);
	if (!storage_info || !storage_info->Invalid())	return;

	if (item_id != storage_info->item_id)	return;

	std::vector<int> change_index;
	change_index.clear();

	out.item_id = item_id;
	out.num = storage_info->num;

	//更新背包数据
	storage_info->num = (num >= storage_info->num ? 0 : storage_info->num - num);
	out.num = storage_info->num == 0 ? out.num : num;

	change_index.push_back(storage_index);

	//清空格子信息，移动最后的物品填补空位
	if (0 == storage_info->num)
	{
		//维护map
		this->updateItemMap(storage_info->item_id, storage_index, MAP_OPER_TYPE_DEL);
		storage_info->Reset();

		int change_idx = this->resortStorage(storage_index);
		if (-1 != change_idx)	change_index.push_back(change_idx);
		this->count--;
	}

	//将发生变动的数组推送

	return;
}

void Bag::DiscardItem(int storage_indx)
{
	ItemData* storage_info = this->getStorageByidx(storage_indx);
	if (!storage_info)	return;

	std::vector<int> change_indxe;
	change_indxe.clear();

	this->updateItemMap(storage_info->item_id, storage_indx, MAP_OPER_TYPE_DEL);
	storage_info->Reset();
	change_indxe.push_back(storage_indx);

	//将最后一个元素拉上来
	int change_idx = this->resortStorage(storage_indx);
	if (-1 != change_idx)	change_indxe.push_back(change_idx);

	this->count--;
}

void Bag::ArrangeBag()
{
	std::unordered_map<int, int> storage_item_map;
	storage_item_map.clear();

	//遍历所有的格子
	for (auto it = m_item_vec_map.begin(); it != m_item_vec_map.end(); ++it)
	{
		for (auto vec_it = it->second.begin(); vec_it != it->second.end(); ++vec_it)
		{
			ItemData* storage_info = this->getStorageByidx(*vec_it);
			if (!storage_info)	continue;

			storage_item_map[storage_info->item_id] += storage_info->num;
			storage_info->Reset();
		}
	}
	m_item_vec_map.clear();

	int count = 0;
	//整理塞入
	for (auto it : storage_item_map)
	{
		if (count > MAX_BAG_CAP)	break;

		int pile_limit = this->getItemDataCfgByID(it.first);

		for (; count < MAX_BAG_CAP; count++)
		{
			ItemData* storage_info = this->getStorageByidx(count);
			if (!storage_info)	break;

			this->updateItemMap(it.first, count, MAP_OPER_TYPE_ADD);

			storage_info->item_id = it.first;
			//没有超过最大值
			if (it.second <= pile_limit)
			{
				storage_info->num = it.second;
				count++;
				break;
			}
			else
			{
				storage_info->num = pile_limit;
				it.second -= pile_limit;
			}
		}
	}
	this->count = count;
}

void Bag::Print()
{
	for (int i = 0; i < this->count; ++i)
	{
		std::cout << "格子【" << i + 1 << "】保存道具【" << this->item_list[i].item_id << "】" << this->item_list[i].num << "个" << std::endl;
	}
}

std::vector<int>* Bag::findItemStorageIdxVec(int item_id)
{
	//获取
	auto it = m_item_vec_map.find(item_id);
	if (it == m_item_vec_map.end())	return nullptr;

	return &(it->second);
}

inline int Bag::getItemDataCfgByID(int item_id)
{
	return ItemDataManager::Instance()->GetItemPileLimitNum(item_id);
}

ItemData* Bag::getStorageByidx(int storage_index)
{
	if (storage_index < 0 || storage_index >= MAX_BAG_CAP)	return nullptr;
	return &(this->item_list[storage_index]);
}

int Bag::resortStorage(int storage_index)
{
	if (storage_index < 0 || storage_index >= MAX_BAG_CAP)	return -1;

	//要移动仓库最后一个物品
	if (storage_index == this->count - 1)	return -1;

	ItemData* last_item = this->getStorageByidx(this->count - 1);
	if (!last_item || !last_item->Invalid())	return -1;

	ItemData* storage_info = this->getStorageByidx(storage_index);
	if (!storage_info || storage_info->Invalid())	return -1;

	*(storage_info) = *(last_item);

	//维护map
	this->updateItemMap(last_item->item_id, this->count - 1, MAP_OPER_TYPE_DEL);
	this->updateItemMap(last_item->item_id, storage_index, MAP_OPER_TYPE_ADD);
	last_item->Reset();

	return this->count - 1;
}

void Bag::updateItemMap(int item_id, int index, int oper_type)
{
	//参数非法
	if (index < 0 || index >= MAX_BAG_CAP)	return;

	switch (oper_type)
	{
	case MAP_OPER_TYPE_ADD:
	{
		this->m_item_vec_map[item_id].push_back(index);
	}
	break;

	case MAP_OPER_TYPE_DEL:
	{
		std::vector<int>* idxs = this->findItemStorageIdxVec(item_id);
		if (!idxs)	break;

		for (auto it = (*idxs).begin(); it != (*idxs).end(); ++it)
		{
			//如果位置等于
			if (index == *it)
			{
				it = (*idxs).erase(it);
				break;
			}
		}
	}
	break;

	default:
		break;
	}
}

int main1()
{
	std::cout << "--------origin-------" << std::endl;
	Bag bag;
	bag.PutItems(1001, 10);
	bag.PutItems(1001, 2);
	bag.PutItems(1002, 4);
	bag.PutItems(1002, 3);
	bag.PutItems(1004, 6);
	bag.PutItems(1001, 2);
	bag.PutItems(1004, 6);
	bag.PutItems(1004, 1);
	bag.PutItems(1001, 1);
	bag.Print();
	std::cout << "---------------" << std::endl;

	std::cout << "--------TakeItem-------" << std::endl;
	ItemData item;
	bag.TakeItem(1 - 1, 1001, 2, item);
	bag.Print();
	std::cout << "---------------" << std::endl;

	std::cout << "--------DiscardItem-------" << std::endl;
	bag.DiscardItem(1 - 1);
	bag.Print();
	std::cout << "---------------" << std::endl;

	std::cout << "--------DiscardItem-------" << std::endl;
	bag.DiscardItem(4 - 1);
	bag.Print();
	std::cout << "---------------" << std::endl;

	bag.PutItems(1003, 1);
	std::cout << "--------ArrangeBag-------" << std::endl;
	bag.ArrangeBag();
	bag.Print();
	std::cout << "---------------" << std::endl;

	bag.PutItems(1003, 1);
	bag.Print();
	std::cout << "---------------" << std::endl;
	return 0;
}